#region
/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 
#endregion

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Text;
using Adoor.Expression;
using Adoor.Expression.AST;

namespace Adoor.Relational.SqlDriver
{
	public abstract class CommonSqlDriver: ISqlDriver, IRelationalOperatorEvaluator, IRelationalQueryEvaluator
	{
		protected enum SqlMode { Select, Aggregate, Delete, Update, NonQuery }

		protected abstract CommonSqlDriver Clone();

		public CommonSqlDriver(int paramCount)
		{
			this.paramCount = paramCount;			
		}

		public virtual string GetSelectCommand(DataTable table, ICollection<DataColumn> dataColumns)
		{
			StringBuilder result = new StringBuilder("select ");
			int i = 0;
			foreach (DataColumn dc in dataColumns)
			{
				if (dc.Expression != "")
					continue;
				if (i != 0)
					result.Append(", ");
				++i;
				result.Append(dc.ColumnName);
			}
			result.Append(" from ");
			result.Append(table.TableName);
			return result.ToString();
		}

		protected static bool IsInPrimaryKey(DataColumn dc, DataTable table)
		{
			foreach(DataColumn pk in table.PrimaryKey)
				if (string.Compare(pk.ColumnName, dc.ColumnName, true) == 0)
					return true;
			return false;
		}

		public virtual string GetUpdateCommand(DataTable table, bool updateWhereAll, bool refreshDataFromDatabase, ICollection<DataColumn> dataColumns, LockMode lockMode)
		{
			StringBuilder result = new StringBuilder("update ");
			result.Append(table.TableName);
			switch(lockMode)
			{
				case LockMode.Default:
				default:
				{
				}break;
				case LockMode.RowLock:
				{
					result.Append(" WITH ( ROWLOCK ) ");
				}break;
			}
			result.Append(" SET ");
			int i = 0;

			foreach (DataColumn dc in dataColumns)
			{
				if (dc.ReadOnly || dc.Expression != "" || IsInPrimaryKey(dc, table))
					continue;
				if (i != 0)
					result.Append(", ");
				result.Append(dc.ColumnName);
				result.Append(" = {" + i.ToString() + "}");
				++i;
			}
			result.Append(" where ");
			bool comma = false;
			foreach(DataColumn dc in table.PrimaryKey)
			{
				if (comma)
					result.Append(" and ");
				comma = true;
				result.Append(dc.ColumnName);
				result.Append(" = {" + i.ToString() + "}");
				++i;
			}
			if (updateWhereAll) 
			{
				// TODO
			}
			return result.ToString();
		}

        public virtual string GetInsertCommand(DataTable table, bool refreshDataFromDatabase, ICollection<DataColumn> dataColumns, LockMode lockMode)
		{
			StringBuilder result = new StringBuilder("insert into ");
			result.Append(table.TableName);

			switch(lockMode)
			{
				case LockMode.Default:
				default:
				{
				}break;
				case LockMode.RowLock:
				{
					result.Append(" WITH ( ROWLOCK ) ");
				}break;
			}

			result.Append(" (");
			int i = 0;
			foreach (DataColumn dc in dataColumns)
			{
				if (dc.ReadOnly || dc.Expression != "")
					continue;
				if (i != 0)
					result.Append(", ");
				++i;
				result.Append(dc.ColumnName);
			}
			result.Append(") values (");
			i = 0;
			foreach (DataColumn dc in dataColumns)
			{
				if (dc.ReadOnly || dc.Expression != "")
					continue;
				if (i != 0)
					result.Append(", ");
				result.Append("{" + (i++).ToString() + "}");
			}
			result.Append(")"); 
			return result.ToString();
		}

		public virtual string GetDeleteCommand(DataTable table, bool updateWhereAll, ICollection<DataColumn> dataColumns, LockMode lockMode)
		{
			StringBuilder result = new StringBuilder("delete from ");
			result.Append(table.TableName);

			switch(lockMode)
			{
				case LockMode.Default:
				default:
				{
				}break;
				case LockMode.RowLock:
				{
					result.Append(" WITH ( ROWLOCK ) ");
				}break;
			}

			result.Append(" where ");
			int i = 0;
			foreach(DataColumn dc in table.PrimaryKey)
			{
				if (i != 0)
					result.Append(" and ");
				result.Append(dc.ColumnName);
				result.Append(" = {" + i.ToString() + "}");
				++i;
			}
			//			if (updateWhereAll)
			//				foreach (DataColumn dc in dataColumns)
			//				{
			//					// TODO
			//				}
			return result.ToString();
		}

		public string DeleteCommand(RelationalQuery query)
		{
			this.paramCount = 0;
            this.results = new List<string>();
			string[] results;
			Evaluate(SqlMode.Delete, query, null, null, Int64.MaxValue, "", null, null, out results);
			return results[0];
		}

		public string[] SelectCommand(RelationalQuery query)
		{
			this.paramCount = 0;
            this.results = new List<string>();
			string[] results;
			Evaluate(SqlMode.Select, query, null, null, Int64.MaxValue, "", null, null, out results);
			return results;
		}

		public string UpdateCommand(RelationalQuery query)
		{
			this.paramCount = 0;
            this.results = new List<string>();
			string[] results;
			Evaluate(SqlMode.Update, query, null, null, Int64.MaxValue, "", null, null, out results);
			return results[0];
		}

		public string[] NonQueryCommand(RelationalQuery query)
		{
			this.paramCount = 0;
            this.results = new List<string>();
			string[] results;
			Evaluate(SqlMode.NonQuery, query, null, null, Int64.MaxValue, "", null, null, out results);
			return results;
		}

		public string CountCommand(RelationalQuery query)
		{
			this.paramCount = 0;
            this.results = new List<string>();
			string[] results;
			Evaluate(SqlMode.Select, query, null, null, Int64.MaxValue, "", null, null, out results);
			return "select count(*) from (" + results[0] + ") C";
		}

		void IRelationalQueryEvaluator.EvaluateDelete(DeleteQuery d)
		{
			EvaluateDelete(d);
		}

		protected virtual void EvaluateDelete(DeleteQuery d)
		{
			if(d.InnerQueries != null && d.InnerQueries.Count > 0)
			{
                results = new List<string>();
				foreach(DeleteQuery dq in d.InnerQueries)
				{
					EvaluateDelete(dq);
				}
				return;
			}

			StringBuilder sb = new StringBuilder();
			sb.Append("delete ");
			sb.Append( Escape(d.SourceName) );

			sb.Append( " from ");
			sb.Append( Escape(d.SourceName) );
			sb.Append( " as ");
			sb.Append( Escape("mainr"));
			sb.Append( " inner join ( ");
					
			sb.Append( " select " );
			sb.Append( Escape(d.ExpressionNameOID.Value) );
			
			d.RelationOperator.EvaluateFrom(this);
			string select = this.Result.ToString();
			sb.Append(select.Substring(select.ToLower().IndexOf(" from ")));
			this.Result.Length = 0;

			sb.Append(" ) as ");
			sb.Append(Escape("subr"));
			sb.Append(" on ");
			sb.Append( "  ");
			sb.Append( GenerateExpression(new ExpressionName("subr", d.ExpressionNameOID.Value)));
			sb.Append( " = " );
			sb.Append( GenerateExpression(new ExpressionName("mainr", d.ExpressionNameOID.Value)));
			
			results.Add(sb.ToString());

		}

		void IRelationalQueryEvaluator.EvaluateUpdate(UpdateQuery u)
		{
			EvaluateUpdate(u);
		}

		protected virtual void EvaluateUpdate(UpdateQuery u)
		{
			if(u.InnerQueries != null && u.InnerQueries.Count > 0)
			{
                results = new List<string>();
				foreach(UpdateQuery uq in u.InnerQueries)
				{
					EvaluateUpdate(uq);
				}
				return;
			}
				
			switch(u.UpdateQueryType)
			{
				case UpdateQuery.UpdateQueryTypes.Update:
				{
					StringBuilder sb = new StringBuilder();
					sb.Append("update ");
					sb.Append( Escape(u.SourceName) );
					sb.Append(" set ");
					bool needComma = false;
					SetExpression seOid = (SetExpression) u.SetExpressions[0];
					for(int i = 1; i < u.SetExpressions.Count; i++)
					{
						SetExpression se = (SetExpression) u.SetExpressions[i];
						if(needComma)
							sb.Append(", ");
						needComma = true;
						sb.Append( Escape(se.SetExpressionName.Value) );
						sb.Append(" = ");
						sb.Append(GenerateExpression(se.ValueExpression));
					}
					sb.Append(" from ");
					sb.Append( Escape(u.SourceName) );
					sb.Append( " inner join ( select * " );
					u.RelationOperator.EvaluateFrom(this);
					string select = this.Result.ToString();
					sb.Append(select.Substring(select.ToLower().IndexOf(" from ")));
					this.Result.Length = 0;
					sb.Append( " ) " );
					sb.Append( Escape("subreq") );
					sb.Append( " on " );
					sb.Append( GenerateExpression(new ExpressionName("subreq", seOid.SetExpressionName.Value)));
					sb.Append( " = " );
					sb.Append( GenerateExpression(new ExpressionName(u.SourceName, seOid.SetExpressionName.Value)));

					results.Add(sb.ToString());
				}break;
				case UpdateQuery.UpdateQueryTypes.Insert:
				{
					StringBuilder sb = new StringBuilder();
					sb.Append("insert into ");
					SetExpression seOid = (SetExpression) u.SetExpressions[0];
					SetExpression se = (SetExpression) u.SetExpressions[1];
					sb.Append( Escape(u.SourceName) );
					sb.Append( " ( ");
					sb.Append( Escape(se.SetExpressionName.Qualifier) );
					sb.Append( "," );
					sb.Append( Escape(se.SetExpressionName.Value) );
					sb.Append( " ) ");
					sb.Append( " select " );
					sb.Append( GenerateExpression(seOid.SetExpressionName) );
					sb.Append( "," );
					sb.Append( GenerateExpression(se.ValueExpression) );

					u.RelationOperator.EvaluateFrom(this);
					string select = this.Result.ToString();
					sb.Append(select.Substring(select.ToLower().IndexOf(" from ")));
					this.Result.Length = 0;

					results.Add(sb.ToString());
				}break;
				case UpdateQuery.UpdateQueryTypes.Delete:
				{
					StringBuilder sb = new StringBuilder();
					sb.Append("delete ");
					sb.Append( Escape(u.SourceName) );

					sb.Append( " from ");
					sb.Append( Escape(u.SourceName) );
					sb.Append( " as ");
					sb.Append( Escape("mainr"));
					sb.Append( " inner join ( ");
					
					SetExpression seOid = (SetExpression) u.SetExpressions[0];
					SetExpression se = (SetExpression) u.SetExpressions[1];
					sb.Append( " select " );
					sb.Append( GenerateExpression(seOid.SetExpressionName) );
					sb.Append( " as " );
					sb.Append( Escape(se.SetExpressionName.Qualifier) );
					sb.Append( "," );
					sb.Append( GenerateExpression(se.ValueExpression) );
					sb.Append( " as " );
					sb.Append( Escape(se.SetExpressionName.Value) );

					u.RelationOperator.EvaluateFrom(this);
					string select = this.Result.ToString();
					sb.Append(select.Substring(select.ToLower().IndexOf(" from ")));
					this.Result.Length = 0;

					sb.Append(" ) as ");
					sb.Append(Escape("subr"));
					sb.Append(" on ");
					sb.Append( "  ");
					sb.Append( GenerateExpression(new ExpressionName("subr", se.SetExpressionName.Qualifier)));
					sb.Append( " = " );
					sb.Append( GenerateExpression(new ExpressionName("mainr", se.SetExpressionName.Qualifier)));
					sb.Append( " and " );
					sb.Append( GenerateExpression(new ExpressionName("subr", se.SetExpressionName.Value)));
					sb.Append( " = " );
					sb.Append( GenerateExpression(new ExpressionName("mainr", se.SetExpressionName.Value)));

					results.Add(sb.ToString());
				}break;
			}

		}

		void IRelationalQueryEvaluator.EvaluateInsert(InsertQuery i)
		{
			EvaluateInsert(i);
		}

		protected virtual void EvaluateInsert(InsertQuery i)
		{
			result = new StringBuilder("insert into ");
			result.Append(Escape(i.SourceName));
			bool needComma = false;
			result.Append(" ( ");
			foreach(DataColumn dci in i.DataColumns)
			{
				if(needComma)
					result.Append(", ");
				needComma = true;

				result.Append(Escape(dci.ColumnName));
			}
			result.Append(" ) ");

			if(i.Values != null)
			{
				result.Append("values ( ");
				needComma = false;
				foreach(ExpressionNode en in i.Values)
				{
					if(needComma)
						result.Append(", ");
					needComma = true;

					result.Append(GenerateExpression(en));
				}
				result.Append(") ");
			}
			else
			{
				string query = result.ToString();
				result.Length = 0;
				SelectCommand(i.InnerQuery);
				result.Insert(0, query);
			}
		}

		void IRelationalQueryEvaluator.EvaluateScan(ScanQuery s)
		{
			EvaluateScan(s);
		}

		protected virtual void EvaluateScan(ScanQuery s)
		{
			string tableName = TableName(s.SourceName);
			if (this.mode == SqlMode.Delete)
			{
				result = new StringBuilder("delete ");
				result.Append(tableName);
			}
			else 
			{
				result = new StringBuilder(this.mode == SqlMode.Aggregate ? "" : "select");
				if (this.distinct)
					result.Append(" distinct");
				if (this.top != Int64.MaxValue)
				{
					result.Append(" TOP ");
					result.Append(this.top);
				}
				if (this.mode == SqlMode.Select)
				{
					result.Append(' ');
					StringBuilder cc = new StringBuilder();
					if (this.columns != null)
					{
						foreach(SelectExpression c in this.columns)
						{
							if (cc.Length != 0)
								cc.Append(',');
							string fullname = "";
							fullname += GenerateExpression(c.Expr);
							cc.Append(fullname);

							if(c.Alias != "" && c.Alias != null)
								cc.AppendFormat(" {0}",Escape(c.Alias));

						}
					}
					else
					{
						foreach(DataColumn dci in s.DataColumns)
						{
							if (cc.Length != 0)
								cc.Append(',');
							if(dci.Expression != null && dci.Expression != "")
							{
								cc.Append(dci.Expression);
								cc.Append(" ");
								cc.Append(dci.ColumnName);
							}
							else
							{
								cc.Append(dci.ColumnName);
							}
						}
					}
					if (cc.Length == 0)
						result.Append("1");
					else
						result.Append(cc);
				}
			}
			result.Append(" from ");
			result.Append(tableName);
			if (this.alias == "")
				this.alias = tableName;
			if (this.alias != "")
			{
				result.Append(' ');
				result.Append(Escape(this.alias));
			}
			if (filter != "")
			{
				result.Append(" where ");
				result.Append(filter);
			}

			if (groupBy != null)
			{
				result.Append(" group by ");
				for (int i = 0; i < groupBy.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(groupBy[i].Expr));					
				}

				if (having != null)
				{
					result.Append(" having ");
					result.Append(GenerateExpression(having.Expr));					
				}
			}

			this.groupBy = null;
			this.having = null;

			if (sort != null)
			{
				result.Append(" order by ");
				for (int i = 0; i < sort.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(sort[i].Expr));
					if (sort[i].SortType == ScannerToken.Desc)
						result.Append(" desc");
				}
			}
			this.sort = null;
		}

		void IRelationalQueryEvaluator.EvaluateUnqualifier(UnqualifierQuery q)
		{
			q.Source.EvaluateFrom(this);
			// nothing ?
		}

		void IRelationalQueryEvaluator.EvaluateUnion(UnionQuery u)
		{
			result = new StringBuilder( this.alias == string.Empty || this.mode == SqlMode.Aggregate ? "" : "select");
			if (this.distinct)
				result.Append(" distinct");
			if (this.top != Int64.MaxValue)
			{
				result.Append(" top ");
				result.Append(this.top);
			}

			if(this.alias != string.Empty)
			{
				if (this.mode == SqlMode.Select )
				{
					result.Append(' ');
					string cc = "";

					if (this.columns != null)
					{
						foreach (SelectExpression c in this.columns)
						{
							if (cc != "")
								cc += ",";
							cc += GenerateExpression(c.Expr);
							if(c.Alias != "" && c.Alias != null)
								cc += " " + Escape(c.Alias);
						}
					}
					else
					{
						foreach(DataColumn dci in u.DataColumns)
						{
							if (cc.Length != 0)
								cc += ',';
							if(dci.Expression != null && dci.Expression != "")
							{
								cc += dci.Expression;
								cc += " ";
								cc += dci.ColumnName;
							}
							else
							{
								cc += dci.ColumnName;
							}						
						}
					}
					if (cc == "")
						result.Append('1');
					else
						result.Append(cc);
				}

				result.Append(" from ");
			}

			CommonInternalDriver driver2 = CreateInternalDriver();

			driver2.Evaluate(u, this.alias);
			result.Append(driver2.Result);

			if(this.alias == string.Empty)
				return;
			
			string cond1 = driver2.Condition;

			if (this.filter != "") 
			{
				result.Append(" where ");
				result.Append(this.filter);
			}

			if (groupBy != null)
			{
				result.Append(" group by ");
				for (int i = 0; i < groupBy.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(groupBy[i].Expr));					
				}

				if (having != null)
				{
					result.Append(" having ");
					result.Append(GenerateExpression(having.Expr));					
				}
			}

			this.groupBy = null;
			this.having = null;

			if (sort != null)
			{
				result.Append(" order by ");
				for (int i = 0; i < sort.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(sort[i].Expr));
					if (sort[i].SortType == ScannerToken.Desc)
						result.Append(" desc");
				}
			}
			this.sort = null;
		}

		protected string FullName(ExpressionName c)
		{
			return GenerateExpression(c) + " " + Escape(c.Value);
		}

		void IRelationalOperatorEvaluator.EvaluateAlias(AliasOperator a)
		{
			string oldAlias = this.alias;
			if (oldAlias == "")
				this.alias = a.Alias;
			a.Source.EvaluateFrom(this);
			this.alias = oldAlias;
		}

		void IRelationalOperatorEvaluator.EvaluateJoin(JoinOperator j)
		{
			EvaluateJoin(j);
		}

		protected virtual CommonInternalDriver CreateInternalDriver()
		{
			return new CommonInternalDriver(this);
		}

		protected virtual void EvaluateJoin(JoinOperator j)
		{
			result = new StringBuilder(this.mode == SqlMode.Aggregate ? "" : "select");
			if (this.distinct)
				result.Append(" distinct");
			if (this.top != Int64.MaxValue)
			{
				result.Append(" top ");
				result.Append(this.top);
			}

			if (this.mode == SqlMode.Select)
			{
				result.Append(' ');
				string cc = "";

				if (this.columns != null)
				{
					foreach (SelectExpression c in this.columns)
					{
						if (cc != "")
							cc += ",";
						cc += GenerateExpression(c.Expr);
						if(c.Alias != "" && c.Alias != null)
							cc += " " + Escape(c.Alias);						
					}
				}
				else 
				{
					foreach(ExpressionName c in j.Columns)
					{
						if (cc != "")
							cc += ",";
						cc += FullName(c);
					}
				}
				if (cc == "")
					result.Append('1');
				else
					result.Append(cc);
			}

			result.Append(" from ");

			CommonInternalDriver driver2 = CreateInternalDriver();

			driver2.Evaluate(j.Source1, j.Correlation);
			result.Append(driver2.Result);
			result.Append(j.IsOuterJoin ? " left outer join " :" join ");

			string cond1 = driver2.Condition;

			driver2.Evaluate(j.Source2, j.Alias);
			result.Append(driver2.Result);
			string cond2 = driver2.Condition;
			if (cond2 != "")
			{
				if (cond1 != "")
					cond1 += " and ";
				cond1 += cond2;
			}
			result.Append(" on ");
			result.Append(Escape(j.Alias));
			result.Append('.');
			result.Append(j.Column2);
			result.Append(" = ");
			result.Append(Escape(j.Correlation));
			result.Append('.');
			result.Append(j.Column1);

			if (cond1 != "")
			{
				result.Append(" and ");
				result.Append(cond1);
			}
			if (this.filter != "") 
			{
				//if (j.IsOuterJoin)
				result.Append(" where ");
				//else
				//result.Append(" and ");
				result.Append(this.filter);
			}

			if (groupBy != null)
			{
				result.Append(" group by ");
				for (int i = 0; i < groupBy.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(groupBy[i].Expr));					
				}

				if (having != null)
				{
					result.Append(" having ");
					result.Append(GenerateExpression(having.Expr));					
				}
			}

			this.groupBy = null;
			this.having = null;

			if (sort != null)
			{
				result.Append(" order by ");
				for (int i = 0; i < sort.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(sort[i].Expr));
					if (sort[i].SortType == ScannerToken.Desc)
						result.Append(" desc");
				}
			}
			this.sort = null;
		}

		void IRelationalOperatorEvaluator.EvaluateCross(CrossOperator c)
		{
			EvaluateCross(c);
		}

		void IRelationalOperatorEvaluator.EvaluateCrossQuery(CrossQueryOperator c)
		{
			EvaluateCrossQuery(c);
		}

		protected virtual void EvaluateCrossQuery(CrossQueryOperator j)
		{
			result = new StringBuilder(this.mode == SqlMode.Aggregate ? "" : "select");
			if (this.distinct)
				result.Append(" distinct");
			if (this.top != Int64.MaxValue)
			{
				result.Append(" top ");
				result.Append(this.top);
			}

			if (this.mode == SqlMode.Select)
			{
				result.Append(' ');
				string cc = "";

				if (this.columns != null)
				{
					foreach(SelectExpression c in this.columns)
					{
						if (cc != "")
							cc += ",";
						cc += GenerateExpression(c.Expr);
						if(c.Alias != "" && c.Alias != null)
							cc += " " + Escape(c.Alias);
					}
				}
				else 
				{
					foreach(ExpressionName c in j.Columns)
					{
						if (cc != "")
							cc += ",";
						cc += FullName(c);
					}
				}
				if (cc == "")
					result.Append('1');
				else
					result.Append(cc);
			}

			result.Append(" from ");

			CommonInternalDriver driver2 = CreateInternalDriver();

			driver2.Evaluate(j.Source1, "");
			string cond1 = driver2.Condition;

			result.Append(driver2.Result);
			if(j.IsOuterJoin)
				result.Append(" left outer join  (");
			else
				result.Append(" inner join  (");

			CommonSqlDriver csd = Clone();
			//string oldResult = result.ToString();
			//string cross = csd.SelectCommand(j.Source2Query);

			result.Append(csd.SelectCommand(j.Source2Query)[0]);
			result.Append(" ) as ");
			result.Append(j.Alias);
			result.Append(" on ");
			result.Append(GenerateExpression(j.JoinCondition));
			
			if (this.filter != "") 
			{
				if (cond1 != "")
					cond1 += " and ";
				cond1 += this.filter;
			}
			if (cond1 != "")
			{
				result.Append(" where ");
				result.Append(cond1);
			}

			if (groupBy != null)
			{
				result.Append(" group by ");
				for (int i = 0; i < groupBy.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(groupBy[i].Expr));					
				}

				if (having != null)
				{
					result.Append(" having ");
					result.Append(GenerateExpression(having.Expr));					
				}
			}

			this.groupBy = null;
			this.having = null;

			if (sort != null)
			{
				result.Append(" order by ");
				for (int i = 0; i < sort.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(sort[i].Expr));
					if (sort[i].SortType == ScannerToken.Desc)
						result.Append(" desc");
				}
			}
			this.sort = null;
		}

		void IRelationalOperatorEvaluator.EvaluateScanQueryOperator(ScanQueryOperator s)
		{
			EvaluateScanQueryOperator(s);
		}

		protected virtual void EvaluateScanQueryOperator(ScanQueryOperator s)
		{
			result = new StringBuilder(this.mode == SqlMode.Aggregate ? "" : "select");
			if (this.distinct)
				result.Append(" distinct");
			if (this.top != Int64.MaxValue)
			{
				result.Append(" top ");
				result.Append(this.top);
			}

			if (this.mode == SqlMode.Select)
			{
				result.Append(' ');
				string cc = "";

				if (this.columns != null)
				{
					foreach(SelectExpression c in this.columns)
					{
						if (cc != "")
							cc += ",";
						cc += GenerateExpression(c.Expr);
						if(c.Alias != "" && c.Alias != null)
							cc += " " + Escape(c.Alias);
					}
				}
				else 
				{
					foreach(ExpressionName c in s.Columns)
					{
						if (cc != "")
							cc += ",";
						cc += FullName(c);
					}
				}
				if (cc == "")
					result.Append('1');
				else
					result.Append(cc);
			}

			result.Append(" from (");

			CommonSqlDriver csd = Clone();
			//string oldResult = result.ToString();
			//string cross = csd.SelectCommand(j.Source2Query);

			result.Append(csd.SelectCommand(s.ScanQuery)[0]);
			result.Append(" ) as ");
			result.Append(s.Alias);
			
			if (this.filter != "") 
			{
				result.Append(" where ");
				result.Append(this.filter);
			}

			if (groupBy != null)
			{
				result.Append(" group by ");
				for (int i = 0; i < groupBy.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(groupBy[i].Expr));					
				}

				if (having != null)
				{
					result.Append(" having ");
					result.Append(GenerateExpression(having.Expr));					
				}
			}

			this.groupBy = null;
			this.having = null;

			if (sort != null)
			{
				result.Append(" order by ");
				for (int i = 0; i < sort.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(sort[i].Expr));
					if (sort[i].SortType == ScannerToken.Desc)
						result.Append(" desc");
				}
			}
			this.sort = null;
		}

		protected virtual void EvaluateCross(CrossOperator j)
		{
			result = new StringBuilder(this.mode == SqlMode.Aggregate ? "" : "select");
			if (this.distinct)
				result.Append(" distinct");
			if (this.top != Int64.MaxValue)
			{
				result.Append(" top ");
				result.Append(this.top);
			}

			if (this.mode == SqlMode.Select)
			{
				result.Append(' ');
				string cc = "";

				if (this.columns != null)
				{
					foreach(SelectExpression c in this.columns)
					{
						if (cc != "")
							cc += ",";
						cc += GenerateExpression(c.Expr);
						if(c.Alias != "" && c.Alias != null)
							cc += " " + Escape(c.Alias);
					}
				}
				else 
				{
					foreach(ExpressionName c in j.Columns)
					{
						if (cc != "")
							cc += ",";
						cc += FullName(c);
					}
				}
				if (cc == "")
					result.Append('1');
				else
					result.Append(cc);
			}

			result.Append(" from ");

			CommonInternalDriver driver2 = CreateInternalDriver();

			driver2.Evaluate(j.Source1, "");			
			result.Append(driver2.Result);
			//result.Append(", ");

			if(j.IsOuterJoin)
				result.Append(" left outer join  ");
			else
				result.Append(" inner join ");

			string cond1 = driver2.Condition;

			driver2.Evaluate(j.Source2, j.Alias);
			result.Append(driver2.Result);
			

			//string oldResult = result.ToString();
			//string cross = csd.SelectCommand(j.Source2Query);

			result.Append(" on ");

			if(j.JoinCondition == null)
				result.Append(GenerateExpression(new ExpressionBinary(ScannerToken.Eq, new ExpressionPrimary(ScannerToken.Integer, "1"), new ExpressionPrimary(ScannerToken.Integer, "1"))));
			else
				result.Append(GenerateExpression(j.JoinCondition));



			string cond2 = driver2.Condition;
			if (cond2 != "")
			{
				if (cond1 != "")
					cond1 += " and ";
				cond1 += cond2;
			}

			if (this.filter != "") 
			{
				if (cond1 != "")
					cond1 += " and ";
				cond1 += this.filter;
			}
			if (cond1 != "")
			{
				result.Append(" where ");
				result.Append(cond1);
			}

			if (groupBy != null)
			{
				result.Append(" group by ");
				for (int i = 0; i < groupBy.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(groupBy[i].Expr));					
				}

				if (having != null)
				{
					result.Append(" having ");
					result.Append(GenerateExpression(having.Expr));					
				}
			}

			this.groupBy = null;
			this.having = null;

			if (sort != null)
			{
				result.Append(" order by ");
				for (int i = 0; i < sort.Length; i++)
				{
					if (i != 0)
						result.Append(", ");
					result.Append(GenerateExpression(sort[i].Expr));
					if (sort[i].SortType == ScannerToken.Desc)
						result.Append(" desc");
				}
			}
			this.sort = null;
		}

		void IRelationalOperatorEvaluator.EvaluateFilter(FilterOperator f)
		{
			string oldFilter = this.filter;
			if (this.filter != "")
				this.filter += " and "; // select from (select from S where c1) where c2 => select from S where c1 and c2
			this.filter += GenerateExpression(f.Condition);
			f.Source.EvaluateFrom(this);
			this.filter = oldFilter;
		}

		void IRelationalOperatorEvaluator.EvaluateSort(SortOperator s)
		{
			if (this.mode == SqlMode.Select)
			{
				if (this.sort == null)
					this.sort = s.SortOrder;
				else if (s.SortOrder != null)
				{
					SortExpression[] newSort = new SortExpression[this.sort.Length + s.SortOrder.Length];
					int j = 0;
					for (int i = 0; i < this.sort.Length; i++)
						newSort[j++] = this.sort[i];
					for (int i = 0; i < s.SortOrder.Length; i++)
						newSort[j++] = s.SortOrder[i];
					this.sort = newSort;
				}
			}
			s.Source.EvaluateFrom(this);
			this.sort = null;
		}

		void IRelationalOperatorEvaluator.EvaluateGroupBy(GroupByOperator g)
		{
			if (this.mode == SqlMode.Select)
			{
				if (this.groupBy == null)
					this.groupBy = g.GroupByColumns;				
				else if (g.GroupByColumns != null)
				{
					GroupByExpression[] newGroupBy = new GroupByExpression[this.groupBy.Length + g.GroupByColumns.Length];
					int j = 0;
					for (int i = 0; i < this.groupBy.Length; i++)
						newGroupBy[j++] = this.groupBy[i];
					for (int i = 0; i < g.GroupByColumns.Length; i++)
						newGroupBy[j++] = g.GroupByColumns[i];
					this.groupBy = newGroupBy;
				}

				if (this.having == null)
					this.having = g.Having;
			}
			g.Source.EvaluateFrom(this);
			this.sort = null;
		}

		void IRelationalOperatorEvaluator.EvaluateIntersect(IntersectOperator i)
		{
			CommonSqlDriver driver2 = Clone();
			string innerSql = driver2.SelectCommand(i.Source2.Filter("[" + i.Correlation1 + "].[" + i.Column1 + "] = [" + i.Correlation2 + "].[" + i.Column2 + "]").Project())[0];
			string oldFilter = this.filter;
			if (this.filter != "")
				this.filter += " and ";
			if (i.IsMinus)
				this.filter = "not exists (" + innerSql + ")";
			else
				this.filter = "exists (" + innerSql + ")";
			i.Source1.EvaluateFrom(this);
			this.filter = oldFilter;
		}

		void IRelationalQueryEvaluator.EvaluateProject(ProjectQuery p)
		{
			ICollection<SelectExpression> oldColumns = this.columns;
			if (this.columns != null)
			{
                List<SelectExpression> remappedColumns = new List<SelectExpression>();
				foreach(SelectExpression oc in this.columns)
				{
					foreach(SelectExpression pc in p.Columns)
					{
						ExpressionName ocName = oc.Expr as ExpressionName; // TODO: use a visitor instead
						if (ocName == null)
							continue;  
						
                        if (ocName.Value == pc.Alias && (ocName.Qualifier == "" ))
						{
							ExpressionName pcName = pc.Expr as ExpressionName; // TODO: use a visitor instead of a cast
							
                            remappedColumns.Add(new SelectExpression(oc.Alias, new ExpressionName(ocName.Qualifier, pcName.Value)));
							goto Found;
						}
					}
					throw new Exception("error in column named  " + oc.Alias);
				Found:;
				}
				this.columns = remappedColumns;
			}
			else
				this.columns = p.Columns;			

            //foreach(SelectExpression oc in this.columns)
            //{
            //    CommonCorrelationFilteredColumnForwarder.ForwardColumn(oc, p.Source, this);
            //}

			p.Source.EvaluateFrom(this);
			
			this.columns = oldColumns;
		}

		public StringBuilder Result
		{ 
			get { return this.result; }
			set { this.result = value; }
		}		

		protected virtual void Evaluate(SqlMode mode, RelationalQuery query, ICollection<SelectExpression> columns, 
			SortExpression[] sort, Int64 top, string filter, GroupByExpression[] groupBy, HavingExpression having, out string[] results)
		{
			this.mode = mode;
			this.columns = columns;
			this.sort = sort;
			this.top = query.TopCount;
			this.filter = filter;
			this.distinct = query.Distinct;
			this.alias = "";
			this.groupBy = groupBy;
			this.having = having;
			query.EvaluateFrom(this);
			if(this.results != null && this.results.Count > 0)
			{
				results = this.results.ToArray();				
			}
			else
				results = new string[] { this.Result.ToString() };
		}

		protected SqlMode mode;
		protected ICollection<SelectExpression>columns;
		protected SortExpression[] sort;
		protected Int64 top;
		protected string filter;
		protected bool distinct;
		private StringBuilder result = new StringBuilder();
		protected List<string> results = null;
		protected string alias;
		protected GroupByExpression[] groupBy;
		protected HavingExpression having;

		protected int paramCount;

		#region CommonInternalDriver
		protected internal class CommonInternalDriver: IRelationalOperatorEvaluator, IRelationalQueryEvaluator
		{
			private CommonSqlDriver context;
			public CommonInternalDriver(CommonSqlDriver context)
			{
				this.context = context;
			}

			public string Evaluate(RelationalQuery query, string alias)
			{
				this.alias = alias;
				this.result = "";
				this.condition = "";
				query.EvaluateFrom(this);
				return this.Result;
			}

			public string Evaluate(RelationalOperator expression, string alias)
			{
				this.alias = alias;
				this.result = "";
				this.condition = "";
				expression.EvaluateFrom(this);
				return this.Result;
			}


			void IRelationalOperatorEvaluator.EvaluateAlias(AliasOperator a)
			{
				if (this.alias == "")
					this.alias = a.Alias;
				a.Source.EvaluateFrom(this);
			}

			void IRelationalQueryEvaluator.EvaluateScan(ScanQuery s)
			{
				EvaluateScan(s);
			}

			protected virtual void EvaluateScan(ScanQuery s)
			{
				string tableName = TableName(s.SourceName);
				result = tableName;
				if (this.alias != tableName)
					result += " " + Escape(alias);
			}

			void IRelationalQueryEvaluator.EvaluateInsert(InsertQuery i)
			{
				EvaluateInsert(i);
			}

			protected virtual void EvaluateInsert(InsertQuery i)
			{
			}

			void IRelationalQueryEvaluator.EvaluateDelete(DeleteQuery d)
			{
				EvaluateDelete(d);
			}

			protected virtual void EvaluateDelete(DeleteQuery i)
			{
			}

			void IRelationalQueryEvaluator.EvaluateUpdate(UpdateQuery u)
			{
				EvaluateUpdate(u);
			}

			protected virtual void EvaluateUpdate(UpdateQuery u)
			{
				
			}

			void IRelationalOperatorEvaluator.EvaluateJoin(JoinOperator j)
			{
				EvaluateJoin(j);
			}
			
			protected virtual void EvaluateJoin(JoinOperator j)
			{
				string res = "";

				Evaluate(j.Source1, j.Correlation);
				res += this.Result;
				res += j.IsOuterJoin ? " left outer join " : " join ";
				string cond1 = this.Condition;

				this.Evaluate(j.Source2, j.Alias);
				res += this.Result;
				string cond2 = Condition;
				if (cond2 != "")
				{
					if (cond1 != "")
						cond1 += " and ";
					cond1 += cond2;
				}
				res += " on " + Escape(j.Alias) + "." + j.Column2 + " = " + Escape(j.Correlation) + "." + j.Column1;

				if (cond1 != "")
				{
					if (j.IsOuterJoin)
						res += " where ";
					else
						res += " and ";
					res += cond1;
				}
				condition = "";

				result = res;
			}

			void IRelationalOperatorEvaluator.EvaluateCross(CrossOperator c)
			{
				EvaluateCross(c);
			}

			void IRelationalOperatorEvaluator.EvaluateScanQueryOperator(ScanQueryOperator s)
			{
				EvaluateScanQueryOperator(s);
			}
			
			protected virtual void EvaluateScanQueryOperator(ScanQueryOperator s)
			{
				StringBuilder sbResult = new StringBuilder();
				sbResult.Append(" ( ");
				
				CommonSqlDriver csd = this.context.Clone();
				
				string scan = csd.SelectCommand(s.ScanQuery)[0];

				sbResult.Append(scan);
				sbResult.Append(" ) as ");
				sbResult.Append(Escape(s.Alias));
				
				result = sbResult.ToString();
			}

			void IRelationalOperatorEvaluator.EvaluateCrossQuery(CrossQueryOperator c)
			{
				EvaluateCrossQuery(c);
			}
			
			protected virtual void EvaluateCross(CrossOperator j)
			{
				string res = "";

				Evaluate(j.Source1, "");
				res += this.Result;

				if(j.IsOuterJoin)
					res += " left outer join  ";
				else
					res += " inner join ";

				string cond1 = this.Condition;

				this.Evaluate(j.Source2, j.Alias);
				res += this.Result;
			
				//string oldResult = result.ToString();
				//string cross = csd.SelectCommand(j.Source2Query);

				res += " on ";

				if(j.JoinCondition == null)
					res += context.GenerateExpression(new ExpressionBinary(ScannerToken.Eq, new ExpressionPrimary(ScannerToken.Integer, "1"), new ExpressionPrimary(ScannerToken.Integer, "1")));
				else
					res += context.GenerateExpression(j.JoinCondition);

				string cond2 = Condition;
				if (cond2 != "")
				{
					if (cond1 != "")
						cond1 += " and ";
					cond1 += cond2;
				}

				if (cond1 != "")
				{
					res += " where ";
					res += cond1;
				}
				condition = "";

				result = res;
			}

			protected virtual void EvaluateCrossQuery(CrossQueryOperator j)
			{
				Evaluate(j.Source1, "");
				
				StringBuilder sbResult = new StringBuilder(result);
				if(j.IsOuterJoin)
					sbResult.Append(" left outer join  (");
				else
					sbResult.Append(" inner join  (");

				CommonSqlDriver csd = this.context.Clone();
				//string oldResult = result.ToString();
				string cross = csd.SelectCommand(j.Source2Query)[0];

				sbResult.Append(cross);
				sbResult.Append(" ) as ");
				sbResult.Append(j.Alias);
				sbResult.Append(" on ");
				sbResult.Append(this.context.GenerateExpression(j.JoinCondition));

				string cond1 = this.Condition;
				if (cond1 != "")
				{
					sbResult.Append(" where ");
					sbResult.Append("cond1");
				}
				condition = "";

				result = sbResult.ToString();
			}

			void IRelationalQueryEvaluator.EvaluateUnion(UnionQuery u)
			{
				CommonSqlDriver driver = this.context.Clone();
				this.result = "";
				foreach(RelationalQuery op in u.Sources)
				{
					if (this.result != "")
						this.result += " union all ";
					
					string[] results;
					driver.Evaluate(SqlMode.Select, op, null, null, Int64.MaxValue, "", null, null, out results);
					this.result += results[0];
				}
				
				if(this.alias == string.Empty)
					return;

				this.result = "(" + this.result + ") " + Escape(this.alias);
			}

			void IRelationalOperatorEvaluator.EvaluateFilter(FilterOperator f)
			{
				f.Source.EvaluateFrom(this);
				if (this.condition != "")
					this.condition += " and ";
				this.condition += this.context.GenerateExpression(f.Condition);
			}

			void IRelationalOperatorEvaluator.EvaluateSort(SortOperator s)
			{
				CommonSqlDriver driver = this.context.Clone();
				string[] results;
				driver.Evaluate(SqlMode.Select, s.Source.AsQuery(), null, s.SortOrder, Int64.MaxValue, "", null, null, out results);
				result = "(" + driver.Result + ") " + Escape(this.alias);
			}

			void IRelationalOperatorEvaluator.EvaluateGroupBy(GroupByOperator g)
			{
				CommonSqlDriver driver = this.context.Clone();
				string[] results;
				driver.Evaluate(SqlMode.Select, g.Source.AsQuery(), null, null, Int64.MaxValue, "", g.GroupByColumns, g.Having, out results);
				result = "(" + driver.Result + ") " + Escape(this.alias);
			}

			void IRelationalOperatorEvaluator.EvaluateIntersect(IntersectOperator i)
			{
				throw new NotImplementedException();
			}

			void IRelationalQueryEvaluator.EvaluateProject(ProjectQuery p)
			{
				CommonSqlDriver driver = this.context.Clone();
				string[] results;
				driver.Evaluate(SqlMode.Select, p.Source.AsQuery(), p.Columns, null, Int64.MaxValue, "", null, null, out results);
				result = "(" + driver.Result + ") " + Escape(alias);
			}

			void IRelationalQueryEvaluator.EvaluateUnqualifier(UnqualifierQuery u)
			{
				u.Source.EvaluateFrom(this);
				// nothing ?
			}

			public string Result
			{ 
				get { return this.result; }
				set { this.result = value; }
			}
	
			public string Condition
			{
				get { return this.condition; }
				set { this.condition = value; }
			}

			private string alias;
			private string result;
			private string condition;

			protected string TableName(string sourceName)
			{
				return context.TableName(sourceName);
			}
			protected string Escape(string name)
			{
				return context.Escape(name);
			}
		}

		#endregion 

//        protected internal class CommonCorrelationFilteredColumnForwarder : IRelationalOperatorEvaluator, IRelationalQueryEvaluator
//        {
//            private bool match;
//            private SelectExpression exp;
//            private ExpressionCorrelationFilteredNode node;
//            private CommonSqlDriver context;
//            private ExpressionNode forceNode;
//            private string forceNodeQualifier;

//            private CommonCorrelationFilteredColumnForwarder(SelectExpression exp, CommonSqlDriver context)
//            {
//                this.context = context;
//                this.exp = exp;
//                this.node = exp.Expr as ExpressionCorrelationFilteredNode;
//                match = false;
//                forceNode = null;
//                forceNodeQualifier = null;
//            }

//            public static void ForwardColumn(SelectExpression exp, RelationalOperator op, CommonSqlDriver context)
//            {
//                if(exp != null && exp.Expr is ExpressionCorrelationFilteredNode)
//                {
//                    CommonCorrelationFilteredColumnForwarder forwarder = new CommonCorrelationFilteredColumnForwarder(exp, context);
//                    op.EvaluateFrom(forwarder);
//                    exp.Alias = (exp.Expr as ExpressionCorrelationFilteredNode).Qualifier.Value;
////					exp.Expr = new ExpressionName((exp.Expr as ExpressionCorrelationFilteredNode).Qualifier.Qualifier,
////						(exp.Expr as ExpressionCorrelationFilteredNode).Qualifier.Qualifier + "_" + (exp.Expr as ExpressionCorrelationFilteredNode).Qualifier.Value);
//                }
//            }			

//            #region IRelationalQueryEvaluator Members

//            void IRelationalQueryEvaluator.EvaluateInsert(InsertQuery i)
//            {
//                throw new NotImplementedException();
//            }			

//            void IRelationalQueryEvaluator.EvaluateDelete(DeleteQuery d)
//            {
//                throw new NotImplementedException();
//            }

//            void IRelationalQueryEvaluator.EvaluateUpdate(UpdateQuery u)
//            {
//                throw new NotImplementedException();
//            }

//            public void EvaluateScan(ScanQuery s)
//            {				
//                ExpressionNode node = this.node.Nodes[s.SourceName] as ExpressionNode;
//                if(node != null)
//                {
//                    s.DataColumns = addNodeToDataColumn(s, node, s.DataColumns);
//                    match = true;
//                }
//                else if(forceNode != null)
//                {
//                    s.DataColumns = addNodeToDataColumn(s, ExpressionReplace.ReplaceNameQualifer(forceNode, forceNodeQualifier, s.SourceName), s.DataColumns);
//                }
//            }

//            private List<RelationalQuery> alreadyForwardedQueries = new List<RelationalQuery>();
//            private DataColumn[] addNodeToDataColumn(RelationalQuery sourceQuery, ExpressionNode node, DataColumn[] source)
//            {				
//                string key = string.Concat(sourceQuery.GetHashCode());
//                if(!alreadyForwardedQueries.Contains(key))
//                {
//                    alreadyForwardedQueries.Add(key);
//                    DataColumn[] dcis = new DataColumn[source.Length + 1];
//                    source.CopyTo(dcis, 0);
//                    DataColumn dc = new DataColumn(this.node.Qualifier.Value);
//                    dcis[dcis.Length - 1] = new DataColumn(dc);
//                    dcis[dcis.Length - 1].ColumnName = this.node.Qualifier.Qualifier + "_" + this.node.Qualifier.Value;
//                    dcis[dcis.Length - 1].Expression = context.GenerateExpression(node);
//                    return dcis;
//                }
//                return source;
//            }

//            public void EvaluateUnion(UnionQuery u)
//            {
//                if(forceNode != null)
//                {
//                    u.DataColumns = addNodeToDataColumn(u, forceNode, u.DataColumns);	
//                }
//                else
//                {
//                    bool oldMatch = match;
//                    List<RelationalQuery> alNoMatch = new List<RelationalQuery>(u.Sources.Count);
//                    if(alias != null)
//                    {
//                        forceNode = this.node.Nodes[alias] as ExpressionNode;
//                        forceNodeQualifier = alias;
//                    }
//                    else
//                    {
//                        forceNode = null;
//                        forceNodeQualifier = null;
//                    }

//                    foreach(RelationalQuery op in u.Sources)
//                    {
//                        this.match = false;
//                        op.EvaluateFrom(this);						
//                        if(!this.match && forceNode == null)
//                        {
//                            alNoMatch.Add(op);
//                        }						
//                    } 
//                    if(alNoMatch.Count == u.Sources.Count)
//                    {
//                        match = false;
//                    }
//                    else
//                    {
//                        forceNode = this.node.DefaultNode;
//                        forceNodeQualifier = null;
//                        try
//                        {
//                            foreach(RelationalQuery op in alNoMatch)
//                            {
//                                op.EvaluateFrom(this);								
//                            }
//                        }
//                        finally
//                        {
//                            forceNode = null;
//                        }
//                        match = true;
//                    }
//                }
//            }

//            public void EvaluateUnqualifier(UnqualifierQuery u)
//            {
//                u.Source.EvaluateFrom(this);
//            }
			
			
//            public void EvaluateProject(ProjectQuery p)
//            {	
//                if(forceNode != null)
//                {
//                    if(!alreadyForwardedQueries.Contains(p))
//                    {
//                        alreadyForwardedQueries.Add(p);
//                        AliasOperator aliasOp = p.Source as AliasOperator;
//                        string newAlias = alias;
//                        if(aliasOp != null)
//                        {
//                            newAlias = aliasOp.Alias;
//                        }
//                        string colExp = this.node.Qualifier.Qualifier + "_" + this.node.Qualifier.Value;

//                        ArrayList alCols = new ArrayList(p.ColumnInfos);
//                        alCols.Add(new SelectExpression(colExp, ExpressionReplace.ReplaceNameQualifer(forceNode, forceNodeQualifier, newAlias )));
//                        p.ColumnInfos = alCols.ToArray();
//                    }
//                }
//                else
//                {
//                    p.Source.EvaluateFrom(this);
//                    if(match)
//                    {
//                        AliasOperator aliasOp = p.Source as AliasOperator;
//                        if(!alreadyForwardedQueries.Contains(p))
//                        {
//                            if(aliasOp.Source is UnionQuery)
//                            {
							
//                                alreadyForwardedQueries.Add(p);
//                                string newAlias = alias;
//                                if(aliasOp != null)
//                                {
//                                    newAlias = aliasOp.Alias;
//                                }
//                                string colExp = this.node.Qualifier.Qualifier + "_" + this.node.Qualifier.Value;

//                                ArrayList alCols = new ArrayList(p.ColumnInfos);
//                                alCols.Add(new SelectExpression(colExp, new ExpressionName(newAlias, colExp)));
//                                p.ColumnInfos = alCols.ToArray();
							
//                            }
//                            else if(aliasOp.Source is ScanQuery)
//                            {
//                                ScanQuery s = (ScanQuery) aliasOp.Source;
//                                ExpressionNode node = this.node.Nodes[s.SourceName] as ExpressionNode;
//                                if(node != null)
//                                {
//                                    alreadyForwardedQueries.Add(p);
//                                    string newAlias = alias;
//                                    if(aliasOp != null)
//                                    {
//                                        newAlias = aliasOp.Alias;
//                                    }
//                                    string colExp = this.node.Qualifier.Qualifier + "_" + this.node.Qualifier.Value;

//                                    ArrayList alCols = new ArrayList(p.ColumnInfos);
//                                    alCols.Add(new SelectExpression(colExp, node));
//                                    p.ColumnInfos = alCols.ToArray();
//                                }
//                            }
//                        }
//                    }
//                }
//            }

//            #endregion
		
//            #region IRelationalOperatorEvaluator Members

//            private string alias;
//            public void EvaluateAlias(AliasOperator a)
//            {
//                string oldAlias = this.alias;
//                try
//                {
//                    this.alias = a.Alias;
//                    a.Source.EvaluateFrom(this);
//                }
//                finally
//                {
//                    this.alias = oldAlias;
//                }
//            }

//            public void EvaluateJoin(JoinOperator j)
//            {
//                j.Source1.EvaluateFrom(this);
//                j.Source2.EvaluateFrom(this);
//            }

//            public void EvaluateCross(CrossOperator c)
//            {
//                c.Source1.EvaluateFrom(this);
//                c.Source2.EvaluateFrom(this);
//            }

//            public void EvaluateCrossQuery(CrossQueryOperator c)
//            {
//                c.Source1.EvaluateFrom(this);
//                //c.Source2.EvaluateFrom(this);
//            }

//            public void EvaluateScanQueryOperator(ScanQueryOperator s)
//            {
				
//            }

//            public void EvaluateFilter(FilterOperator f)
//            {
//                f.Source.EvaluateFrom(this);
//            }

//            public void EvaluateSort(SortOperator s)
//            {
//                s.Source.EvaluateFrom(this);
//            }

//            public void EvaluateIntersect(IntersectOperator i)
//            {
//                i.Source1.EvaluateFrom(this);
//                i.Source2.EvaluateFrom(this);
//            }

//            public void EvaluateGroupBy(GroupByOperator g)
//            {
//                g.Source.EvaluateFrom(this);
//            }

//            #endregion
//        }

		protected string TableName(string sourceName)
		{
			return sourceName; //TODO: use TableMapping
		}

		protected abstract string Escape(string name);

		protected virtual string GenerateExpression(ExpressionNode en)
		{
			return CommonExpressionStringizer.Evaluate(this, en);
		}

		protected class CommonExpressionStringizer: ExpressionStringizer
		{
			public static string Evaluate(CommonSqlDriver driver, ExpressionNode n)
			{
				CommonExpressionStringizer es = new CommonExpressionStringizer(driver);
				n.Accept(es);
				return es.Result.ToString();
			}

			CommonSqlDriver driver;
			protected CommonExpressionStringizer(CommonSqlDriver driver)
			{
				this.driver = driver;
			}

			public override void VisitFunction(ExpressionFunction f)
			{
				
				if(f.Name.ToLower() == "case")
					VisitFunctionCase(f);
				else if(f.Name.ToLower() == "cast")
					VisitFunctionCast(f);
				else
				{
					base.VisitFunction(f);
				}
				
			}

			public virtual void VisitFunctionCast(ExpressionFunction f)
			{
				if( f.Parameters.Length != 2)
					throw new Exception("case function should have 2 parameters");


				this.Result.Append(" CAST( ");
				f.Parameters[0].Accept(this);
				this.Result.Append(" as ");
			
				StringBuilder sbNewResult = this.Result;
				this.Result = new StringBuilder();
				f.Parameters[1].Accept(this);
				sbNewResult.Append(this.Result.ToString().Replace("'", ""));
				this.Result = sbNewResult;

				this.Result.Append(")");
			}

			public virtual void VisitFunctionCase(ExpressionFunction f)
			{
				this.Result.Append(" CASE ");
				if( f.Parameters.Length < 2)
					throw new Exception("case function should have at least 2 parameters");

				bool elseFound = false;

				foreach(Adoor.Expression.AST.ExpressionNode en in f.Parameters)
				{
					if(!(en is Adoor.Expression.AST.ExpressionFunction))
						throw new Exception("case function can't contains this type of node " + en.GetType().Name);

                    Adoor.Expression.AST.ExpressionFunction fn = (Adoor.Expression.AST.ExpressionFunction)en;

					if(fn.Name.ToLower() == "if")
					{
						if(elseFound)
							throw new Exception("else function should be the last parameter in a case function");
						VisitFunctionCaseIf(fn);
					}
					else if(fn.Name.ToLower() == "else")				
					{
						VisitFunctionCaseElse(fn);
						elseFound = true;
					}
					else
						throw new Exception("function not allowed here " + fn.Name);
				}

				this.Result.Append( " END ");			
			}

			public virtual void VisitFunctionCaseIf(ExpressionFunction f)
			{
				this.Result.Append( " WHEN ");

				if(f.Parameters.Length != 2)
					throw new Exception(" if function must contains 2 paramters in a case function ");
			

				f.Parameters[0].Accept(this);
				this.Result.Append(" THEN ");
				f.Parameters[1].Accept(this);			
			}

			public virtual void VisitFunctionCaseElse(ExpressionFunction f)
			{
				this.Result.Append( " ELSE ");

				if(f.Parameters.Length != 1)
					throw new Exception(" else function must contains 1 paramter in a case function ");

				f.Parameters[0].Accept(this);
			}

			public override void VisitEscape(ExpressionEscape e)
			{
				this.Result.Append(e.Content); // Do not generate curly braces
			}

			public override void VisitPrimary(ExpressionPrimary p)
			{
				if (p.Value == "?")
					this.Result.Append("{" + this.driver.paramCount++ + "}");
				else
					this.Result.Append(p.Value.Replace("{", "{{").Replace("}", "}}")); // curly braces are possible inside character strings
			}

			public override void VisitCorrelationFilteredNode(ExpressionCorrelationFilteredNode c)
			{				
				ExpressionName en = new ExpressionName(c.Qualifier.Qualifier, c.Qualifier.Qualifier + "_" + c.Qualifier.Value);
				en.Accept(this);
			}

			public override void VisitInSubQuery(ExpressionInSubquery j)
			{
				j.Exp.Accept(this);
				this.Result.Append(" IN (");
				CommonSqlDriver csd = this.driver.Clone();
				string[] results;
				csd.Evaluate(SqlMode.Select, (RelationalQuery) j.SubQuery, null, null, -1, "", null, null, out results);
				this.Result.Append(results[0]);
				this.Result.Append(" )");
			}

			public override void VisitExistsSubQuery(ExpressionExistsSubquery j)
			{
				this.Result.Append(" Exists (");
				CommonSqlDriver csd = this.driver.Clone();
				string[] results;
				csd.Evaluate(SqlMode.Select, (RelationalQuery) j.SubQuery, null, null, -1, "", null, null, out results);
				this.Result.Append(results[0]);
				this.Result.Append(" )");
			}
		}

		public virtual string DefaultSelectIsolationLevelQuery
		{
			get
			{
				return string.Empty;
			}
		}

	}
}
